package com.silverhaze.diamond.server.service;

import com.silverhaze.commons.db.datasource.DataSourceListener;
import com.silverhaze.commons.db.datasource.ObjectEntity;
import com.silverhaze.commons.utils.collections.list.MetaArrayList;
import com.silverhaze.commons.utils.collections.list.MetaList;
import com.silverhaze.diamond.common.constants.DiamondConstants;
import com.silverhaze.diamond.common.entity.Service;
import com.silverhaze.diamond.common.event.UIEventEntityChanged;
import com.silverhaze.diamond.common.service.DataSourceServiceRemote;
import com.silverhaze.diamond.server.jms.UIServerEventDispatcher;
import com.silverhaze.diamond.server.util.NullTrigger;
import com.silverhaze.diamond.server.util.ServiceTrigger;
import com.silverhaze.diamond.server.util.Trigger;
import org.jboss.xnio.log.Logger;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: Babanin
 * Date: 31.03.11
 * Time: 0:52
 */
@Remote(value = DataSourceServiceRemote.class)
@Stateless(name = DataSourceServiceRemote.NAME)
public class DataSourceServiceBean implements DataSourceServiceRemote {

    private static final Logger LOGGER = Logger.getLogger(DataSourceServiceRemote.class);

    @PersistenceContext(name = DiamondConstants.JTA_PERSISTENCE_UNIT_NAME)
    private EntityManager entityManager;

    private static final Map<Class, Trigger> triggers = new HashMap<Class, Trigger>();

    static {
        triggers.put(Service.class, new ServiceTrigger());
    }

    public long persist(ObjectEntity objectEntity) {
        long result = -1;

        Trigger trigger = triggers.get(objectEntity.getClass());
        if (trigger == null) {
            trigger = new NullTrigger();
        }

        LOGGER.info("Trigger = " + trigger.getClass().toString() + " is used");

        try {
            trigger.prePersist(objectEntity, entityManager);
            result = entityManager.merge(objectEntity).getId();
            trigger.postPersist(objectEntity, entityManager);

            UIServerEventDispatcher.getInstance().notifyEvent(new UIEventEntityChanged(objectEntity,
                    UIEventEntityChanged.Type.PERSIST));
        } catch (Exception e) {
            LOGGER.error(e, "");
        }

        return result;
    }

    public boolean update(ObjectEntity objectEntity) {
        Trigger trigger = triggers.get(objectEntity.getClass());
        if (trigger == null) {
            trigger = new NullTrigger();
        }

        try {
            trigger.preUpdate(objectEntity, entityManager);
            ObjectEntity merge = entityManager.merge(objectEntity);
            trigger.postUpdate(objectEntity, entityManager);

            UIServerEventDispatcher.getInstance().notifyEvent(new UIEventEntityChanged(merge,
                    UIEventEntityChanged.Type.UPDATE));

            return true;
        } catch (Exception e) {
            LOGGER.error(e, "");
        }

        return false;
    }

    public void remove(ObjectEntity objectEntity) {
        long objId = objectEntity.getId();

        Trigger trigger = triggers.get(objectEntity.getClass());
        if (trigger == null) {
            trigger = new NullTrigger();
        }

        try {
            ObjectEntity managedEntity = entityManager.find(objectEntity.getClass(), objId);

            if (managedEntity != null) {
                trigger.preDelete(objectEntity, entityManager);
                entityManager.remove(managedEntity);
                trigger.postDelete(objectEntity, entityManager);
            }
        } catch (Exception e) {
            LOGGER.error(e, "");
        }

        UIServerEventDispatcher.getInstance().notifyEvent(new UIEventEntityChanged(objectEntity,
                UIEventEntityChanged.Type.DELETE));
    }

    public <T extends ObjectEntity> MetaList<T> get(Class<T> tClass) {
        return new MetaArrayList<T>(entityManager.createQuery("SELECT e FROM " +
                tClass.getName() + " AS e").getResultList());
    }

    public <T extends ObjectEntity> T get(Class<T> tClass, int i) {
        MetaList<T> list = get(tClass);
        if (list.size() > i) {
            return list.get(i);
        }

        return null;
    }

    public List queryList(String s) {
        return entityManager.createQuery(s).getResultList();
    }

    public Object queryUniqueResult(String s) {
        return entityManager.createQuery(s).getSingleResult();
    }

    public void addDataSourceListener(DataSourceListener dataSourceListener) {
    }

    public void removeDataSourceListener(DataSourceListener dataSourceListener) {
    }
}
